#include <stateMachine.h>
int stateMachineManagerInit(struct stateMachineManagerInform *smnger, void *setContext, struct stateMachineBaseInform *setStateBuffer,
                            int setStateSize, int initState)
{
    if (!smnger)
    {
        logerror("");
        return -1;
    }
    if (!(setStateBuffer && setStateSize > 0))
    {
        logerror("");
        return -1;
    }
    smnger->statelist = setStateBuffer;
    smnger->stateSize = setStateSize;
    smnger->stateIdNow = stateMachineInvalidID;
    smnger->stateContext = setContext;
    stateMachineManagerTransition(smnger, initState);
    return 0;
}
int stateMachineManagerRun(struct stateMachineManagerInform *smnger)
{
    int tmpnextStateId;
    if (!smnger)
    {
        logerror("");
        return -1;
    }
    if (!(smnger->statelist && smnger->stateSize > 0))
    {
        logerror("");
        return -1;
    }
    // transition state
    if (smnger->stateIdNext >= 0 && smnger->stateIdNext < smnger->stateSize)
    {
        tmpnextStateId = smnger->stateIdNext;
        if (smnger->stateIdNow >= 0 && smnger->stateIdNow < smnger->stateSize)
        {
            // stateQuit can be null
            if(smnger->statelist[smnger->stateIdNow].stateQuit)
            {
                smnger->statelist[smnger->stateIdNow].stateQuit(&smnger->statelist[smnger->stateIdNow]);
            }
        }
        if (tmpnextStateId != smnger->stateIdNext)
        {
            loginform("%d state next=%d, quit func transition to %d", smnger->stateIdNow, tmpnextStateId, smnger->stateIdNext);
        }
        smnger->stateIdNow = smnger->stateIdNext;
        smnger->stateIdNext = stateMachineInvalidID;
        if (!(smnger->stateIdNow >= 0 && smnger->stateIdNow < smnger->stateSize))
        {
            logerror("init id error:%d", smnger->stateIdNow);
            return -1;
        }
        // stateInit can be null
        if (smnger->statelist[smnger->stateIdNow].stateInit)
        {
            smnger->statelist[smnger->stateIdNow].stateInit(&smnger->statelist[smnger->stateIdNow]);
        }
    }
    // init function changed next state
    if (smnger->stateIdNext >= 0 && smnger->stateIdNext < smnger->stateSize)
    {
        loginform("%d state init func transition to %d", smnger->stateIdNow, smnger->stateIdNext);
        return 0;
    }
    else if (smnger->stateIdNow >= 0 && smnger->stateIdNow < smnger->stateSize)
    {
        // stateRun can't be null
        if (!smnger->statelist[smnger->stateIdNow].stateRun)
        {
            logerror("");
            return -1;
        }
        smnger->statelist[smnger->stateIdNow].stateRun(&smnger->statelist[smnger->stateIdNow]);
    }
    return 0;
}
int stateMachineManagerQuit(struct stateMachineManagerInform *smnger)
{
    if (!smnger)
    {
        logerror("");
        return -1;
    }
    smnger->statelist = NULL;
    smnger->stateSize = 0;
    smnger->stateIdNow = stateMachineInvalidID;
    smnger->stateIdNext = stateMachineInvalidID;
    smnger->stateContext = NULL;
    return 0;
}
int stateMachineManagerTransition(struct stateMachineManagerInform *smnger, int nextStateId)
{
    if (!smnger)
    {
        logerror("");
        return -1;
    }
    if (!(smnger->statelist && smnger->stateSize > 0))
    {
        logerror("");
        return -1;
    }
    if (!(nextStateId >= 0 && nextStateId < smnger->stateSize))
    {
        logerror("set id error:%d,%d", nextStateId, smnger->stateSize);
        return -1;
    }
    smnger->stateIdNext = nextStateId;
    return 0;
}


#if 0
#include <stateMachine.h>
enum MY_CHECK_STATE_ENUM
{
    MY_CHECK_STATE_0 = 0,
    MY_CHECK_STATE_1,
    MY_CHECK_STATE_2,
    MY_CHECK_STATE_3,
    MY_CHECK_STATE_4,
    MY_CHECK_STATE_5,
    MY_CHECK_STATE_6,
};
int stateMachineCheckInit(struct stateMachineBaseInform *thisState)
{
    logdebug("init %d", thisState->stateId);
    switch (thisState->stateId)
    {
    case MY_CHECK_STATE_0:
    {
        stateMachineManagerTransition(thisState->stateManager, MY_CHECK_STATE_1);
        break;
    }
    default:
        break;
    }
    return 0;
}
int stateMachineCheckRun(struct stateMachineBaseInform *thisState)
{
    logdebug("run %d", thisState->stateId);
    switch (thisState->stateId)
    {
    case MY_CHECK_STATE_1:
    {
        stateMachineManagerTransition(thisState->stateManager, MY_CHECK_STATE_2);
        break;
    }
    case MY_CHECK_STATE_3:
    {
        stateMachineManagerTransition(thisState->stateManager, MY_CHECK_STATE_0);
        stateMachineManagerQuit(thisState->stateManager);
        break;
    }
    default:
        break;
    }
    return 0;
}
int stateMachineCheckQuit(struct stateMachineBaseInform *thisState)
{
    logdebug("quit %d", thisState->stateId);
    switch (thisState->stateId)
    {
    default:
        break;
    }
    return 0;
}

int stateMachineCheck2Init(struct stateMachineBaseInform *thisState)
{
    logdebug("init %d", thisState->stateId);
    return 0;
}
int stateMachineCheck2Run(struct stateMachineBaseInform *thisState)
{
    logdebug("run %d", thisState->stateId);
    stateMachineManagerTransition(thisState->stateManager, MY_CHECK_STATE_3);
    return 0;
}
int stateMachineCheck2Quit(struct stateMachineBaseInform *thisState)
{
    logdebug("quit %d", thisState->stateId);
    stateMachineManagerTransition(thisState->stateManager, MY_CHECK_STATE_0);
    return 0;
}

struct stateMachineManagerInform myCheckStateMnger;

struct stateMachineBaseInform myCheckStates[] = {
    stateMachineBaseDeine(stateMachineCheckInit, stateMachineCheckRun, stateMachineCheckQuit, MY_CHECK_STATE_0, &myCheckStateMnger),
    stateMachineBaseDeine(stateMachineCheckInit, stateMachineCheckRun, NULL, MY_CHECK_STATE_1, &myCheckStateMnger),
    stateMachineBaseDeine(NULL, stateMachineCheck2Run, stateMachineCheck2Quit, MY_CHECK_STATE_2, &myCheckStateMnger),
    stateMachineBaseDeine(stateMachineCheckInit, stateMachineCheckRun, stateMachineCheckQuit, MY_CHECK_STATE_3, &myCheckStateMnger),
};

int main()
{
    int tmpflag = 0;
    stateMachineManagerInit(&myCheckStateMnger, NULL, myCheckStates, ARRAY_LEN(myCheckStates), MY_CHECK_STATE_0);
    while (1)
    {
        tmpflag = stateMachineManagerRun(&myCheckStateMnger);
        if(tmpflag < 0)
        {
            break;
        }
        usleep(1000 * 1000);
    }
}
#endif
